import tkinter as tk
from tkinter import ttk, messagebox


def open_crud_dialog(parent, title, fields, data=None, readonly_cols=None):
    """
    General Query/Add/Modify Pop-ups
    :param parent:        Parent window
    :param title:         Window title
    :param fields:        [(column name, whether to add bool), ...]
    :param data:          The original value dictionary is passed in when modifying, and None is passed in when adding/querying.
    :param readonly_cols: List, specifying read-only columns (such as self-increment, primary key)
    :return:              The dictionary {column name: value} filled by the user or None indicates cancellation.
    """
    if readonly_cols is None:
        readonly_cols = []
    top = tk.Toplevel(parent)
    top.title(title)
    top.transient(parent)
    top.grab_set()
    top.geometry("400x600")

    entries = {}
    for idx, (col, is_serial) in enumerate(fields):
        ttk.Label(top, text=col).grid(row=idx, column=0, sticky=tk.W, padx=10, pady=6)
        ent = ttk.Entry(top, width=40)
        ent.grid(row=idx, column=1, sticky=tk.EW, padx=10, pady=6)
        if data and col in data:
            ent.insert(0, data[col])
        if is_serial or col in readonly_cols:
            ent.config(state="readonly")
        entries[col] = ent

    def on_ok():
        res = {col: ent.get() for col, ent in entries.items()}
        top.destroy()
        parent.focus_set()
        parent._crud_result = res

    def on_cancel():
        top.destroy()
        parent.focus_set()
        parent._crud_result = None

    btn_frame = ttk.Frame(top)
    btn_frame.grid(row=len(fields), column=0, columnspan=2, pady=20)
    ttk.Button(btn_frame, text="Confirm", command=on_ok).pack(side=tk.LEFT, padx=10)
    ttk.Button(btn_frame, text="Cancel", command=on_cancel).pack(side=tk.LEFT, padx=10)

    top.columnconfigure(1, weight=1)
    top._crud_result = None
    parent.wait_window(top)
    return parent._crud_result